<?php
/**
 * @see Alinks_Exception
 */
require_once('Alinks/Exception.php');

/**
 * Used to handle and log errors
 *
 * Logs errors as an XML file. Also used to display errors to users when
 * it's possible.
 *
 * Copyright (C) 2008  Sean Hickey
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author Sean Hickey <sean@headzoo.com>
 * @version $Id: Error.php 408 2008-07-05 14:14:41Z sean $
 * @package Alinks_Error
 */
class Alinks_Error
{
	/**
	 * The directory where log files should be written
	 *
	 * @var string
	 */
	protected static $_log_path = '/';
	
	/**
	 * The exception to show to the user
	 *
	 * @var Exception
	 */
	protected static $_show_exception;
	
	/**
	 * The file name containing the extended error information. Used
	 * when showing the error to the user
	 *
	 * @var string
	 */
	protected static $_show_file;
	
	/**
	 * Sets the directory where log files should be written
	 *
	 * @param string $path The path to the directory
	 * @throws Alinks_Exception
	 */
	public static function setLogPath($path)
	{
		if (!is_writable($path)) {
			/**
			 * @see Alinks_Exception
			 */
			require_once('Alinks/Exception.php');
			throw new Alinks_Exception("The directory $path is not writable");
		}
		self::$_log_path = $path;
	}
	
	/**
	 * Returns the set directory where log files are to be written
	 *
	 * @return string
	 */
	public static function getLogPath()
	{
		return self::$_log_path;
	}
	
	/**
	 * Logs an exception
	 *
	 * Writes the contents of the exception to a log file to be
	 * reviewed later.
	 *
	 * @param Alinks_Exception $e The exception
	 * @return string
	 */
	public static function logException(Exception $e)
	{
		$exception_type = get_class($e);
		$traces = $e->getTrace();
		
		$xml = "<?xml version=\"1.0\"?>\r\n";
		$xml .= "<Exception type=\"$exception_type\">\r\n";
		$xml .= "\t<Date>" . date('r') . "</Date>\r\n";
		$xml .= "\t<Message><![CDATA[" . $e->getMessage() . "]]></Message>\r\n";
		$xml .= "\t<Code>" . $e->getCode() . "</Code>\r\n";
		$xml .= "\t<File><![CDATA[" . $e->getFile() . "]]></File>\r\n";
		$xml .= "\t<Line>" . $e->getLine() . "</Line>\r\n";
		$xml .= "\t<Traces>\r\n";
		foreach($traces as $trace) {
			$xml .= "\t\t<Trace>\r\n";
			$xml .= "\t\t\t<File><![CDATA[" . $trace['file'] . "]]></File>\r\n";
			$xml .= "\t\t\t<Line>" . $trace['line'] . "</Line>\r\n";
			$xml .= "\t\t\t<Function>" . $trace['function'] . "</Function>\r\n";
			$xml .= "\t\t\t<Args>\r\n";
			foreach($trace['args'] as $arg) {
				if (is_object($arg)) {
					$xml .= "\t\t\t\t<Arg><![CDATA[" . get_class($arg) . "]]></Arg>\r\n";
				} else {
					$xml .= "\t\t\t\t<Arg><![CDATA[$arg]]></Arg>\r\n";
				}
			}
			$xml .= "\t\t\t</Args>\r\n";
			$xml .= "\t\t</Trace>\r\n";
		}
		$xml .= "\t</Traces>\r\n";
		$xml .= '</Exception>';
		
		$log_file = tempnam(self::$_log_path, 'al');
		file_put_contents($log_file, $xml);
		return $log_file;
	}
	
	/**
	 * Shows the exception message to the user
	 *
	 * Sets up a hook to show the error message to the user.
	 *
	 * @param Exception $e The exception
	 * @param string $file File name where logged exception information was stored
	 */
	public static function showException($e, $file = null)
	{
		self::$_show_exception = $e;
		self::$_show_file = $file;
		add_action('admin_notices', array('Alinks_Error', 'adminNotices'));
	}
	
	/**
	 * Callback to 'admin_notices'
	 *
	 * Shows the exception message for the exception passed to showException().
	 */
	public static function adminNotices()
	{
		global $wp_version;
		/**
		 * @see Alinks_Version
		 */
		require_once('Alinks/Version.php');
		
		?>
		<div id='alinks-warning' class='updated fade-ff0000'>
			<p><strong>aLinks Fatal Error</strong> 
			<?php echo self::$_show_exception->getMessage(); ?></p>
			<?php if (null !== self::$_show_file) : ?>
			<p>Information about this error has been stored in the file <?php echo self::$_show_file; ?>.</p>
			<p>You can help improve aLinks by submitting this error. Click the submit button below, and the contents of
			the <?php echo basename(self::$_show_file); ?> file, along with your version of WordPress, will be sent to
			headzoo.com for analysis. You can review the contents of the report below. <strong>It does not contain any personal information.</strong></p>
			<form method="post" action="http://reports.headzoo.com">
				<textarea name="exception" style="width: 100%; height: 100px;overflow: scroll;background-color: #fff;border: 1px solid #000;">
<?php echo htmlspecialchars(file_get_contents(self::$_show_file)); ?>
				</textarea>
				<input type="hidden" name="report" value="aLinks" />
				<input type="hidden" name="version" value="<?php echo Alinks_Version::VERSION; ?>" />
				<input type="hidden" name="wp_version" value="<?php echo $wp_version; ?>" />
				<label for="alinks_email">Enter your email address if you would like a reply to this error. I can't guarantee that I'll be able
				to respond to every error.</label>
				<input type="text" id="alinks_email" name="email" /> <input type="submit" value="Submit" />
			</form>
			<?php endif; ?>
		</div>
		<?php
	}
}